﻿package zf.data.geom
{
	import flash.geom.Point;

	import zf.Fig;

	/**
	 * Beeline 对象表示二维坐标系统中的某条线。 
	 * 主要的直线方程有 y = k x + b , A x + B y + C =0;
	 * 本类使用方程为： y = k x + b 
	 * @author Mike.zhang
	 * 
	 */
	public class Beeline implements ILine
	{
		private var _k:Number=1;
		private var _b:Number=0;
		//private var _radian:Number=45*Math.PI/180;

		/**
		 * 创建一个新直线,即 y=x 
		 * 
		 * 
		 */
		public function Beeline ()
		{
		}

		/**
		 * 直线方程y=kx+b中的k值 
		 * @return 直线k值
		 * 
		 */
		public function get k ():Number
		{
			return _k;
		}

		public function set k (v:Number):void
		{
			_k=v;
		}

		/**
		 * 直线方程y=kx+b中的b值 
		 * @return 直线k值
		 * 
		 */
		public function get b ():Number
		{
			return _b;
		}

		public function set b (v:Number):void
		{
			_b=v;
		}

		/**
		 * 以弧度为单位返回直线与x轴正方向所成的角，该角度从圆的 x 轴（0 点在其上，0 表示圆心）沿逆时针方向测量。 返回值介于正 pi/2 和负 pi/2 之间。
		 * @return 弧度值
		 * 
		 */
		public function get radian ():Number
		{
			return Math.atan(k);
		}
		/**
		 * 依据坐标系中的两点确定一条直线.两点必须不同，否则会产生 ArgumentError 异常 
		 * @param p1 直线经过的第一个点
		 * @param p2 直线进过的第二个点
		 * @return 经过两点的直线
		 * @throws ArgumentError 如果两点相同则会发生 ArgumentError 异常
		 * 
		 */
		public static  function PtoBeeline (p1:Point,p2:Point):Beeline
		{
			if (p1.equals(p2))
			{
				throw new ArgumentError("确定直线的两点不能相同");
			}
			var pk:Number=(p2.y - p1.y) / (p2.x - p1.x);
			var pb:Number=(p2.x * p1.y - p1.x * p2.y) / p2.x - p1.x;
			var newBeeline:Beeline=new Beeline  ;
			newBeeline.k=pk;
			newBeeline.b=pb;
			return newBeeline;
		}
		/**
		 * 依据k值和过直线的一点p确定一条直线。 
		 * @param vk 直线的k值
		 * @param p 过该直线的一点
		 * @return 直线
		 * 
		 */
		public static  function KtoBeeline (vk:Number,p:Point):Beeline
		{
			var vb:Number=p.y - vk * p.x;
			var bl:Beeline=new Beeline  ;
			bl.k=vk;
			bl.b=vb;
			return bl;
		}

		/**
		 * 检测点p是否碰撞到直线上 
		 * @param p 待测的点
		 * @return 如果碰撞到直线为true,否则为false
		 * 
		 */
		public function hitPoint (p:Point):Boolean
		{
			return k * p.x + b == p.y;
		}
		/**
		 * 检测和直线l的相交情况。 
		 * @param l 要比较的直线
		 * @return 如果没有交点即两直线平行，则返回 null。如果有交点则返回相交点Point对象
		 * 
		 */
		public function hitBeeline (l:Beeline):Point
		{
			if (k == l.k)
			{
				return null;
			}
			var xx:Number=b - l.b / l.k - k;
			var yy:Number=xx * k + b;
			return new Point(xx,yy);
		}
		/**
		 * 获取与线l所成的夹角，返回值在 0 和 pi/2 之间的数 
		 * @param l 直线
		 * @return 夹角弧度
		 * 
		 */
		public function lineAngle (l:ILine):Number
		{
			//return radian-l.radian;
			var n:Number=Math.abs(Math.atan(l.k - k / 1 + k * l.k));
			return n;
		}
		/**
		 * 检测两条直线是否相等
		 * @param l 要比较的直线
		 * @return 相等返回true
		 * 
		 */
		public function equals (l:Beeline):Boolean
		{
			return k == l.k && b == l.b;
		}
		/**
		 * 获取过点p到直线的垂直线
		 * @param p 直线的经过点
		 * @return 直线
		 * 
		 */
		public function getVline (p:Point):Beeline
		{
			var cl:Beeline=new Beeline  ;
			cl.k=-1 / k;
			cl.b=p.x / k + p.y;
			return cl;
		}
		/**
		 * 计算点到直线的最短距离(即过该点的与直线垂直的线段长度) 
		 * @param p 要经过的点
		 * @return 距离
		 * 
		 */
		public function pointDistance (p:Point):Number
		{
			//d=Math.abs(a x0 + b y0 + c)/Math.sqrt(a*a + b*b);
			if (hitPoint(p))
			{
				return 0;
			}
			//var cl:Beeline=getVline(p);
			//var po:Point=this.hitBeeline(cl);
			//return Formula.distance(p.x,p.y,po.x,po.y);

			return Math.abs(k * p.x - p.y + b) / Math.sqrt(k * k + 1);
		}
		/**
		 * 将直线向X,Y轴分别移动x,y个距离后形成新的直线 
		 * @param x X轴上移动的距离
		 * @param y Y轴上移动的距离
		 * @return 直线
		 * 
		 */
		public function move (x:Number=0,y:Number=0):Beeline
		{
			var newL:Beeline=new Beeline  ;
			newL.k=k;
			newL.b=b - y + k * x;
			return newL;
		}
		/**
		 * 将直线依点p旋转 radian 弧度后得到的新直线
		 * @param radian 旋转的弧度
		 * @param p 旋转的参考点
		 * @return 直线
		 * 
		 */
		public function turn (radian:Number,p:Point=null):Beeline
		{

			//(x,y)绕任一点（x0，y0）的旋转θ角变换公式为
			//x’=xcos(θ )- ysin(θ) - x0cos(θ)+y0sin(θ)+x0

			//y’=xsin(θ)+ycos(θ) - x0sin(θ) - y0cos(θ)+y0

			if (p == null)
			{
				p=new Point  ;
			}
			var ca:Number=Math.cos(radian);
			var sa:Number=Math.sin(radian);
			var x1:Number=- b * sa - p.x * ca + p.y * sa + p.x;
			var y1:Number=b * ca - p.x * sa - p.y * ca + p.y;
			var x2:Number=- b * ca / k - p.x * ca + p.y * sa + p.x;
			var y2:Number=- b * sa / k - p.x * sa - p.y * ca + p.y;
			//var newL:Beeline=new Beeline;
			//newL.k=(k*Math.cos(radian)-Math.sin(radian))/(Math.cos(radian)+k*Math.sin(radian));
			//newL.b=b/(Math.cos(radian)+k*Math.sin(radian));
			//return newL;
			return Beeline.PtoBeeline(new Point(x1,y1),new Point(x2,y2));
		}
		/**
		 * 返回包含 k 和 b 值的字符串，其格式为 (k=n,b=m)
		 * @return 直线的表现形式
		 * 
		 */
		public function toString ():String
		{
			return "(k=" + Fig.toDecimal(k) + " b=" + Fig.toDecimal(b) + ")";
		}
	}
}